﻿using Gxrtbtc.Ptl;
using KafkaUtil;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using NewLife;
using NewLife.Log;
using NewLife.Net;
using NewLife.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PtlSave.Util;
using PtlSvr;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using static CommonModel.Util.ParseSvr;
using GrpcPtlSvr;
using Grpc.Core;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Configuration;
using Microsoft.Extensions.Logging;

namespace PtlSvrPrj
{
    class Program
    {
        static void Main(string[] args)
        {
            XTrace.UseConsole();
            jsonPath = "cfg/config.json";
            XTrace.WriteLine("load config.json ...");
            //读取配置文件
            cfg = CommonUtil.GetJson(jsonPath);
            if (cfg == null)
            {
                XTrace.WriteLine("load config err");
                return;
            }

            XTrace.WriteLine("Server Start...");
            //PtlServer();
            new Thread(PtlServer).Start();
            //Console.ReadKey();
            Thread.Sleep(Timeout.InfiniteTimeSpan);
        }

        /*
         * 入口
         */
        private static string jsonPath = "cfg/config.json";
        private static TimerX _timer;
        public static NetServer _server;
        public static JObject cfg;
        private static void PtlServer()
        {
            //kafka服务地址
            string[] hosts = new string[] { cfg["KafkaSettings"]["BootstrapServers"].ToString() };
            //kafka生产者配置
            KafkaProducerOptions producerOptions = new KafkaProducerOptions
            {
                BootstrapServers = hosts,
                InitializeCount = 3,
                Key = "kafka",
                Topic = cfg["KafkaSettings"]["Topic"].ToString()  //需手工新增
            };
            //kafka生产者配置 解析错误数据保存
            KafkaProducerOptions producerErrOptions = new KafkaProducerOptions
            {
                BootstrapServers = hosts,
                InitializeCount = 3,
                Key = "kafka",
                Topic = cfg["KafkaSettings"]["TopicErr"].ToString()  //需手工新增
            };
            //监听端口
            int Port = CommonUtil.IsInt(cfg["ListenPort"].ToString()) ? int.Parse(cfg["ListenPort"].ToString()) : 8000;
            int GrpcPort = CommonUtil.IsInt(cfg["GrpcPort"].ToString()) ? int.Parse(cfg["GrpcPort"].ToString()) : 5000;

            //动态库dll路径
            string LibPath = cfg["LibPath"].ToString();
            //xml配置文件路径
            string xmlPath = cfg["xmlPath"].ToString();
            string reloadXml = cfg["reloadXml"].ToString();
            if ("TRUE".Equals(reloadXml.ToUpper()))
            {
                CommonUtil.SetJson(jsonPath, "reloadXml", "false");
            }
            else
            {
                xmlPath = "";
            }

            //MySQL数据库连接串
            // "Data Source=server;Database=mydb;User ID=username;Password=pwd;Command Logging=false";
            string connectionString = cfg["MySQLSettings"]["ConnString"].ToString();
            //MySQL数据库版本
            string version = cfg["MySQLSettings"]["Version"].ToString();// "5.7.17";

            string ignoreIps = cfg["ignoreIps"].ToString();
            string SessionTimeout = cfg["SessionTimeout"].ToString();

            PtlLoader ptlLoader = new PtlLoader(connectionString, version, LibPath, xmlPath);
            if (!ptlLoader.mysqlConn)
            {
                XTrace.WriteLine("mysql connect error, service failed to start");
                return;
            }

            //实例化服务端，指定端口，同时在Tcp/Udp/IPv4/IPv6上监听
            var svr = new PtlNetServer(ignoreIps)
            {
                ptlLoader = ptlLoader,
                producerOptions = producerOptions,
                producerErrOptions = producerErrOptions,
                filter = false,  //是否使用过滤机制
                Port = Port,
                SessionTimeout = CommonUtil.IsInt(SessionTimeout) ? int.Parse(SessionTimeout) : 30,  //会话超时时间。默认0秒，使用SocketServer默认值20*60秒（20分钟）
                Log = XTrace.Log,
                ProtocolType = NetType.Udp, //这里固定只监听udp
                SessionLog = XTrace.Log,
                StatPeriod = 30,
                Tracer = new DefaultTracer { Period = 15, Log = XTrace.Log },
#if DEBUG
                SocketLog = XTrace.Log,
                LogSend = true,
                LogReceive = true,
#endif
            };
            svr.Start();
            _server = svr;

            new Thread((ThreadStart)delegate { StartGrpc(GrpcPort); }).Start();

            //定时显示性能数据
            _timer = new TimerX(ShowStat, svr, 100, 1000) { Async = true };

        }

        private static void StartGrpc(int port)
        {
            XTrace.WriteLine("GRPC服务启动");
            //开启GRPC服务
            CreateHostBuilder(new string[] { port.ToString() }).Build().Run();
        }

        /*
         * 开启GRPC服务
         */
        private static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    int port = int.Parse(args[0]);
                    webBuilder.UseStartup<GRPCStartup>()
                    .UseKestrel(opt =>{})
                    .ConfigureAppConfiguration((builderContext, config) =>
                    {
                        config.AddJsonFile("appsettings.json", optional: false);    //加载配置文件
                    })
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseUrls("http://*:" + port.ToString() + ";https://*:" + (port + 1).ToString());
                });

        /*
         * 定时显示性能数据
         */
        private static void ShowStat(Object state)
        {
            var msg = "";
            if (state is NetServer ns)
            { 
                msg = ns.GetStat();
            }
            if (!msg.IsNullOrEmpty())
            { 
                Console.Title = msg;
            } 
        }
    }
}
